/*****************************************************************************
*
*  PROJECT:     Native Executive
*  LICENSE:     See LICENSE in the top level directory
*  FILE:        NativeExecutive/CExecutiveManager.cond.internal.h
*  PURPOSE:     Internal implementation header of conditional variables
*  DEVELOPERS:  Martin Turski <wordwhirl@outlook.de>
*
*  Multi Theft Auto is available from http://www.multitheftauto.com/
*
*****************************************************************************/

#ifndef _EXECUTIVE_MANAGER_CONDVAR_INTERNAL_
#define _EXECUTIVE_MANAGER_CONDVAR_INTERNAL_

BEGIN_NATIVE_EXECUTIVE

struct CCondVarImpl;

struct condVarNativeEnv
{
    struct condVarThreadPlugin : public hazardPreventionInterface
    {
        // We need to be a information node for conditional variables to know
        // that we are waiting for signals. This is required in user-space to
        // cleanly serve termination logic.

        void Initialize( CExecThreadImpl *thread );
        void Shutdown( CExecThreadImpl *thread );

        void TerminateHazard( void ) override;

        // We use the threadState lock to prevent premature interruption of hazard init.
        // Initialization entails pushing the hazard on the stack and getting
        // into wait-state. Init has to be atomic.

        CCondVarImpl *waitingOnVar;
    };

    executiveManagerFactory_t::pluginOffset_t _condVarThreadPluginOffset;

    inline void Initialize( CExecutiveManagerNative *nativeExec )
    {
        // Register a plugin for each thread that holds synchronization object maintenance.
        this->_condVarThreadPluginOffset = nativeExec->threadPlugins.RegisterDependantStructPlugin <condVarThreadPlugin> ();
    }

    inline void Shutdown( CExecutiveManagerNative *nativeExec )
    {
        // Terminate our plugins.
        if ( ExecutiveManager::threadPluginContainer_t::IsOffsetValid( this->_condVarThreadPluginOffset ) )
        {
            nativeExec->threadPlugins.UnregisterPlugin( this->_condVarThreadPluginOffset );

            this->_condVarThreadPluginOffset = ExecutiveManager::threadPluginContainer_t::INVALID_PLUGIN_OFFSET;
        }
    }

    inline condVarThreadPlugin* GetThreadCondEnv( CExecThreadImpl *thread ) const
    {
        return ExecutiveManager::threadPluginContainer_t::RESOLVE_STRUCT <condVarThreadPlugin> ( thread, this->_condVarThreadPluginOffset );
    }
};

typedef PluginDependantStructRegister <condVarNativeEnv, executiveManagerFactory_t> condNativeEnvRegister_t;

extern condNativeEnvRegister_t condNativeEnvRegister;


struct CCondVarImpl : public CCondVar
{
    CCondVarImpl( CExecutiveManagerNative *execMan );
    ~CCondVarImpl( void );

    void Wait( CReadWriteWriteContextSafe <>& ctxLock );
    void Signal( void );

    CExecutiveManagerNative *manager;

    std::condition_variable_any condVarInternal;
};

END_NATIVE_EXECUTIVE

#endif //_EXECUTIVE_MANAGER_CONDVAR_INTERNAL_